package com.atwisdom.star.core.bsl.planner.Impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.DateUtils;
import com.atwisdom.star.core.bsl.planner.SaleOrderBslService;
import com.atwisdom.star.core.bsl.planner.entity.*;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;


@Service
@Data
@NoArgsConstructor
public class SaleOrderBslServiceImpl implements SaleOrderBslService {
    private LogicInstanceDslServiceImpl logicInstanceDslService;
    private HierInstanceDslService hierInstanceDslService;
    private MaterialBslServiceImpl materialBslService;
    private ProductBomBslServiceImpl productBomBslService;

    @Autowired
    public void setLogicInstanceDslService(LogicInstanceDslServiceImpl logicInstanceDslService) {
        this.logicInstanceDslService = logicInstanceDslService;
    }

    @Autowired
    public void setHierInstanceDslService(HierInstanceDslService hierInstanceDslService) {
        this.hierInstanceDslService = hierInstanceDslService;
    }

    @Autowired
    public void setMaterialBslService(MaterialBslServiceImpl materialBslService) {
        this.materialBslService = materialBslService;
    }

    @Autowired
    public void setProductBomBslService(ProductBomBslServiceImpl productBomBslService) {
        this.productBomBslService = productBomBslService;
    }

    //订单信息
    private List<SaleOrder> saleOrders = new ArrayList<>();
    //销售订单按背番、发货日期分组发货量汇总数据列表
    private List<SaleOrderSummary> saleOrderSummaryList = new ArrayList<>();
    //当前正在处理的销售订单组
    private SaleOrderSummary currentSaleOrderSummary;
    //订制订单明细
    private List<SaleOrderSub> trialOrderSubs = new ArrayList<>();
    //开始时间
    private String startDate;
    //结束时间
    private String endDate;

    private List<String> saleOrderBCodeList = new ArrayList<>();


    /**
     * 初始化按订单生产的MRP的基础数据
     *
     * @param dataObj 由客户传到后端的参数
     */
    public void initSalePlanMRP(JSONObject dataObj) {
        JSONObject param = dataObj.getJSONObject("param");
        Date startTime = param.getDate("startTime");
        Date endTime = param.getDate("endTime");

        if (startTime == null) {
            throw new BusinessException("999999", "销售订单交货期开始日期（startDate）不能为空");
        }

        if(endTime ==null){
            throw new BusinessException("999999", "销售订单交货期结束日期（endDate）不能为空");
        }

        LocalDate today = LocalDate.now();
        if(DateUtils.ConvertDateToLocalDate(startTime).isBefore(today)){
            throw new BusinessException("999999", "销售订单交货期开始日期（startDate）不能小于或等于当前日期");
        }

        startDate = DateUtils.getLocalDateFormat(DateUtils.ConvertDateToLocalDate(startTime), "yyyy-MM-dd 00:00:00");
        endDate = DateUtils.getLocalDateFormat(DateUtils.ConvertDateToLocalDate(endTime), "yyyy-MM-dd 23:59:59");
        this.initSaleOrder(startDate, endDate);
    }

    /**
     * 返回销售订单数量
     *
     * @return
     */
    @Override
    public void initSaleOrder(String startDate, String endDate) {
        this.saleOrders = new ArrayList<>();
        this.trialOrderSubs = new ArrayList<>();
        this.saleOrderSummaryList = new ArrayList<>();
        this.saleOrderBCodeList = new ArrayList<>();
        String condition = " deliveryDate >='" + startDate + "' AND deliveryDate <= '" + endDate + "' AND isApproved == 1 ";
        List<JSONObject> saleOrderList = this.logicInstanceDslService.query(condition, "SaleOrder", null);
        List<SaleOrderSub> saleOrderSubs = new ArrayList<>();
        for (JSONObject jsonObject : saleOrderList) {
            Integer id = jsonObject.getInteger("id");
            JSONObject orderValues = jsonObject.getJSONObject("values");
            String code = orderValues.getString("code");
            Date orderDate = orderValues.getDate("date");
            Date deliveryDate = orderValues.getDate("deliveryDate");
            Boolean isApproved = orderValues.getBoolean("isApproved");
            Boolean isTrial = orderValues.getBoolean("isTrial");
            isTrial = isTrial == null ? false : isTrial;
            JSONObject hier = jsonObject.getJSONObject("hier");
            JSONArray content = hier.getJSONArray("content");
            if(content == null || content.size() < 1){
                System.out.println("销售订单没有明细数据，将不参与MRP运算");
                continue;
            }

            List<SaleOrderSub> saleOrderSubList = new ArrayList<>();
            for (int i = 0; i < content.size(); i++) {
                JSONObject contentJson = content.getJSONObject(i);
                String nodeId = contentJson.getString("nodeId");
                if ("root".equalsIgnoreCase(nodeId)) {
                    continue;
                }

                Integer detailId = contentJson.getInteger("id");
                JSONObject values = contentJson.getJSONObject("values");
                String materialPCode = values.getString("material_pcode");
                String materialBCode = values.getString("material_bcode");
                String materialModel = values.getString("material_model");
                String materialSpec = values.getString("material_spec");
                String materialUnit = values.getString("material_unit");
                Integer trialDuration = values.getInteger("trialDuration");
                String trialEquipments = values.getString("trialEquipments");
                Integer quantity = values.getInteger("quantity") == null ? 0 : values.getInteger("quantity");
                Double price = values.getDouble("price");

                SaleOrderSub saleOrderSub = new SaleOrderSub();
                saleOrderSub.setId(detailId);
                saleOrderSub.setOrderId(id);
                saleOrderSub.setCode(code);
                saleOrderSub.setDate(orderDate);
                LocalDate localDate = DateUtils.ConvertDateToLocalDate(deliveryDate);
                saleOrderSub.setDeliveryDate(localDate);
                saleOrderSub.setMaterialPCode(materialPCode);
                saleOrderSub.setMaterialBCode(materialBCode);
                saleOrderSub.setMaterialModel(materialModel);
                saleOrderSub.setMaterialSpec(materialSpec);
                saleOrderSub.setMaterialUnit(materialUnit);
                saleOrderSub.setQuantity(quantity);
                saleOrderSub.setPrice(price);
                saleOrderSub.setTrial(isTrial);
                saleOrderSub.setTrialDuration(trialDuration);
                saleOrderSub.setTrialEquipments(new ArrayList<>());
                if(StringUtils.isNotBlank(trialEquipments)){
                    trialEquipments = trialEquipments.replace("[", "").replace("]", "");
                    List<String> equipmentIds = Arrays.asList(trialEquipments.split(","));
                    equipmentIds.forEach(eid->{
                        saleOrderSub.getTrialEquipments().add(Long.valueOf(eid));
                    });
                }
                saleOrderSubList.add(saleOrderSub);
                saleOrderSubs.add(saleOrderSub);
            }
            SaleOrder saleOrder = new SaleOrder();
            saleOrder.setId(id);
            saleOrder.setCode(code);
            saleOrder.setDate(orderDate);
            saleOrder.setDeliveryDate(deliveryDate);
            saleOrder.setApproved(isApproved);
            saleOrder.setSaleOrderSubs(saleOrderSubList);
            saleOrders.add(saleOrder);
        }
        this.trialOrderSubs.addAll(saleOrderSubs.stream().filter(o -> o.isTrial()).collect(toList()));

        // 获取明日按库存生产的物料
        LocalDate today = LocalDate.now();
        LocalDate tomorrow = today.plusDays(1);
        List<String> materialBCodes  = saleOrderSubs.stream().filter(o -> o.getDeliveryDate().isEqual(tomorrow)).map(o -> o.getMaterialBCode()).collect(toList());
        List<SaleOrderSub> safeSaleOrderSubs = initSafeStockOrder(materialBCodes,tomorrow);
        saleOrderSubs.addAll(safeSaleOrderSubs);

        Map<String, Map<LocalDate, Integer>> saleOrderSubMap = saleOrderSubs.stream()
                .collect(groupingBy(SaleOrderSub::getMaterialBCode,
                        groupingBy(SaleOrderSub::getDeliveryDate, summingInt(SaleOrderSub::getQuantity))));
        this.saleOrderSummaryList = saleOrderSubMap.entrySet().stream()
                .flatMap(majorEntry -> majorEntry.getValue().entrySet().stream()
                        .map(subEntry -> new SaleOrderSummary(majorEntry.getKey(), subEntry.getKey(), subEntry.getValue(), 0)))
                .sorted(Comparator.comparing(SaleOrderSummary::getDeliveryDate))
                .collect(Collectors.toList());
    }

    public void initTrialOrder(String condition) {
        this.saleOrders = new ArrayList<>();
        this.trialOrderSubs = new ArrayList<>();
        List<JSONObject> saleOrderList = this.logicInstanceDslService.query(condition, "SaleOrder", null);
        List<SaleOrderSub> saleOrderSubs = new ArrayList<>();
        for (JSONObject jsonObject : saleOrderList) {
            Integer id = jsonObject.getInteger("id");
            JSONObject orderValues = jsonObject.getJSONObject("values");
            String code = orderValues.getString("code");
            Date orderDate = orderValues.getDate("date");
            Date deliveryDate = orderValues.getDate("deliveryDate");
            Boolean isApproved = orderValues.getBoolean("isApproved");
            Boolean isTrial = orderValues.getBoolean("isTrial");
            isTrial = isTrial == null ? false : isTrial;
            JSONObject hier = jsonObject.getJSONObject("hier");
            JSONArray content = hier.getJSONArray("content");
            if(content == null || content.size() < 1){
                System.out.println("试制订单没有明细数据，将不参与MRP运算");
                continue;
            }
            List<SaleOrderSub> saleOrderSubList = new ArrayList<>();
            for (int i = 0; i < content.size(); i++) {
                JSONObject contentJson = content.getJSONObject(i);
                String nodeId = contentJson.getString("nodeId");
                if ("root".equalsIgnoreCase(nodeId)) {
                    continue;
                }

                Integer detailId = contentJson.getInteger("id");
                JSONObject values = contentJson.getJSONObject("values");
                String materialPCode = values.getString("material_pcode");
                String materialBCode = values.getString("material_bcode");
                String materialModel = values.getString("material_model");
                String materialSpec = values.getString("material_spec");
                String materialUnit = values.getString("material_unit");
                Integer trialDuration = values.getInteger("trialDuration");
                String trialEquipments = values.getString("trialEquipments");
                Integer quantity = values.getInteger("quantity") == null ? 0 : values.getInteger("quantity");
                Double price = values.getDouble("price");

                SaleOrderSub saleOrderSub = new SaleOrderSub();
                saleOrderSub.setId(detailId);
                saleOrderSub.setOrderId(id);
                saleOrderSub.setCode(code);
                saleOrderSub.setDate(orderDate);
                LocalDate localDate = DateUtils.ConvertDateToLocalDate(deliveryDate);
                saleOrderSub.setDeliveryDate(localDate);
                saleOrderSub.setMaterialPCode(materialPCode);
                saleOrderSub.setMaterialBCode(materialBCode);
                saleOrderSub.setMaterialModel(materialModel);
                saleOrderSub.setMaterialSpec(materialSpec);
                saleOrderSub.setMaterialUnit(materialUnit);
                saleOrderSub.setQuantity(quantity);
                saleOrderSub.setPrice(price);
                saleOrderSub.setTrial(isTrial);
                saleOrderSub.setTrialDuration(trialDuration);
                saleOrderSub.setTrialEquipments(new ArrayList<>());
                if(StringUtils.isNotBlank(trialEquipments)){
                    trialEquipments = trialEquipments.replace("[", "").replace("]", "");
                    List<String> equipmentIds = Arrays.asList(trialEquipments.split(","));
                    equipmentIds.forEach(eid->{
                        saleOrderSub.getTrialEquipments().add(Long.valueOf(eid));
                    });
                }
                saleOrderSubList.add(saleOrderSub);
                saleOrderSubs.add(saleOrderSub);
            }
            SaleOrder saleOrder = new SaleOrder();
            saleOrder.setId(id);
            saleOrder.setCode(code);
            saleOrder.setDate(orderDate);
            saleOrder.setDeliveryDate(deliveryDate);
            saleOrder.setApproved(isApproved);
            saleOrder.setSaleOrderSubs(saleOrderSubList);
            saleOrders.add(saleOrder);
        }

        this.trialOrderSubs.addAll(saleOrderSubs.stream().filter(o -> o.isTrial()).collect(toList()));
    }

    public List<SaleOrderSub> initSafeStockOrder(List<String> materialBCodes, LocalDate deliveryDate) {
        Map<String, String> materialAttrMap = this.materialBslService.getMaterialAttrMap();

        // 使用 Stream 进行过滤，并获取 Key 集合
        List<String> bCodeList = materialAttrMap.entrySet().stream()
                .filter(entry -> "produce".equalsIgnoreCase(entry.getValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        List<Material> materials = this.materialBslService.getMaterials();
        List<SaleOrderSub> saleOrderSubs = new ArrayList<>();
        List<ProductBomLevel> productBomLevelList = new ArrayList<>();
        for (String bcode : bCodeList) {
            if(materialBCodes.contains(bcode)){
                continue;
            }

            Material material = materials.stream().filter(m -> m.getBcode().equalsIgnoreCase(bcode) && m.getSafeStock()!=null && m.getSafeStock() > 0 ).findFirst().orElse(null);
            if(material==null){
                continue;
            }
            ProductBomLevel productBomLevel = productBomLevelList.stream().filter(p -> p.getMaterialBCode().equalsIgnoreCase(bcode)).findFirst().orElse(null);
            if(productBomLevel==null){
                this.productBomBslService.buildProductBomLevel(bcode);
                List<ProductBomLevel> productBomLevels = this.productBomBslService.getProductBomLevels();
                productBomLevelList.addAll(productBomLevels);
            }else{
                continue;
            }
            SaleOrderSub saleOrderSub = new SaleOrderSub();
            saleOrderSub.setDate(new Date());
            saleOrderSub.setDeliveryDate(deliveryDate);
            saleOrderSub.setMaterialPCode(material.getPcode());
            saleOrderSub.setMaterialBCode(material.getBcode());
            saleOrderSub.setMaterialModel(material.getModel());
            saleOrderSub.setMaterialSpec(material.getSpec());
            saleOrderSub.setMaterialUnit(material.getUnit());
//            saleOrderSub.setQuantity(material.getMinBatch());
            saleOrderSub.setQuantity(0);
            saleOrderSub.setPrice(material.getReferToPrice());
            saleOrderSub.setTrial(false);
            saleOrderSub.setTrialDuration(0);
            saleOrderSub.setTrialEquipments(new ArrayList<>());
            saleOrderSubs.add(saleOrderSub);
        }
        return saleOrderSubs;
    }
}
